home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / utility / srdisk13.zip / SRDISK.C < prev    next >
C/C++ Source or Header  |  1992-01-18  |  39KB  |  1,331 lines

  1. /*
  2. **      ReSizeable RAMDisk formatter
  3. **
  4. **      Copyright (c) 1992 Marko Kohtala
  5. **
  6. **      Some documentation and license available in accompanying file
  7. **      SRDISK.DOC. If not, contact author by sending E-mail from
  8. **
  9. **              Internet, Bitnet etc. to 'Marko.Kohtala@hut.fi'
  10. **              CompuServe to '>INTERNET:Marko.Kohtala@hut.fi'
  11. **
  12. **      or by calling Airline QBBS, 24H, HST, V.32, V.42, MNP,
  13. **      +358-0-8725380, and leaving mail to me, Marko Kohtala.
  14. **
  15. **      In general, this is FREEWARE.
  16. **
  17. **      To compile with Borland C++ 2.0: bcc -Z -O srdisk.c
  18. **      To compile with Borland C++ 3.0: bcc -O2 srdisk.c
  19. **
  20. */
  21.  
  22. #define VERSION "1.30"
  23.  
  24. /* History
  25.  
  26. 1.00 09-06-91 Initial release
  27.  
  28. 1.10 06-09-91
  29.  
  30. - Added full support for multiple FATs. 1.00 had the /F switch, but no
  31.   support for it in formatter.
  32.  
  33. - Updated to IOCTL_msg versio 1.10 so that media byte is no longer used
  34.   to indicate the media change but to indicate the drive is RAM disk.
  35.  
  36. - Some minor fixes.
  37.  
  38. 1.20 04-10-1991
  39.  
  40. - Fixed name of program by adding the missing 'Re' to 'Sizeable'.
  41.  
  42. - Added 16 bit FAT support; more 'sizeable' disks that had over 4077
  43.   clusters were not operational. Due to DOS's inconsistent behaviour,
  44.   disks with over 4077 and under 4088 clusters (or over 65518, possible
  45.   with 128 byte clusters and 8M disk size) are avoided by making
  46.   clusters bigger.
  47.  
  48. - Added DOS lookalike disk formats via switch /F.
  49.  
  50. - The FAT number is now defined via switch /A instead of /F.
  51.  
  52. - The time of format is stored in volume label.
  53.  
  54. - Upgraded to IOCTL_msg version 1.20 which tells the type of memory used
  55.   by the driver.
  56.  
  57. - Disallow sectors greater than 512 bytes as DOS can not handle them
  58.   properly but rather crashes when it encounters them.
  59.  
  60. - Allow clusters up to 8 kilobytes.
  61.  
  62. - Enhanced help.
  63.  
  64. 1.30 18-01-1992
  65.  
  66. - Changed to freeware from public domain
  67.  
  68. - Changed the driver control from IOCTL calls to multiplex interrupt.
  69.  
  70. - Added support for over 32M RAM drives (up to 4096M). Over 32M drives
  71. need DOS 4+ because they use over 0xFFFF sectors.
  72.  
  73. - Added /V switch for program verbosity control. /Y now only forces the
  74. disk format, it does not make the program less verbose.
  75.  
  76. - Support for chained drivers. These drivers all contribute memory for
  77. the same virtual drive. Added switch /M to control how much memory may
  78. be used by each driver in the chain.
  79.  
  80. - Formatting reads the root directory to find out if there is anything
  81. that would be destroyed. If not, it will not ask for permission to
  82. destroy.
  83.  
  84. - Added /E switch to set environment variables SRDISKn to show srdisk
  85. drives.
  86.  
  87. - Scans Drive Parameter Table on DOS 2 and 3 to find the drive letters,
  88. if necessary.
  89.  
  90. */
  91.  
  92. #include <assert.h>
  93. #include <stdlib.h>
  94. #include <stdio.h>
  95. #include <io.h>
  96. #include <dir.h>
  97. #include <dos.h>
  98. #include <string.h>
  99. #include <time.h>
  100.  
  101. typedef unsigned char byte;
  102. typedef unsigned short word;
  103. typedef unsigned long dword;
  104.  
  105. /* Configuration structure internal to device driver (byte aligned) */
  106. #pragma option -a-
  107. #pragma pack(1)
  108. struct dev_hdr {
  109.   struct dev_hdr far *next;
  110.   word attr;
  111.   word strategy;
  112.   word commands;
  113.   byte units;
  114.   union {
  115.     char volume[12];            /* Volume label combined of fields below */
  116.     struct {
  117.       char ID[3];               /* Identification string 'SRD' */
  118.       char memory[4];           /* Memory type string */
  119.       char version[4];          /* Device driver version string */
  120.       char null;
  121.     } s;
  122.   } u;
  123.   byte v_format;                /* Config_s format version */
  124.   struct config_s near *conf;   /* Offset to cofig_s */
  125. };
  126.  
  127. struct config_s {               /* The whole structure */
  128.   byte drive;                   /* Drive letter of this driver */
  129.   byte flags;                   /* Capability flags */
  130.   word (far *disk_IO)(void);    /* Disk I/O routine entry */
  131.   dword (near *malloc_off)(dword _s); /* Memory allocation routine entry offset */
  132.   struct dev_hdr _seg *next;    /* Next chained driver segment */
  133.   dword maxK;                   /* Maximum memory allowed for disk */
  134.   dword size;                   /* Current size in Kbytes */
  135.   dword sectors;                /* Total sectors in this part of the disk */
  136.  
  137.   word BPB_bps;                 /* BPB - bytes per sector */
  138.   /* The rest is removed from chained drivers, used only in the main driver */
  139.   byte BPB_spc;                 /* BPB - sectors per cluster */
  140.   word BPB_reserved;            /* BPB - reserved sectors in the beginning */
  141.   byte BPB_FATs;                /* BPB - number of FATs on disk */
  142.   word BPB_dir;                 /* BPB - root directory entries */
  143.   word BPB_sectors;             /* BPB - sectors on disk (16-bit) */
  144.   byte BPB_media;               /* BPB - identifies the media (default 0xFA) */
  145.   word BPB_FATsectors;          /* BPB - sectors per FAT */
  146.   word BPB_spt;                 /* BPB - sectors per track (imaginary) */
  147.   word BPB_heads;               /* BPB - heads (imaginary) */
  148.   dword BPB_hidden;             /* BPB - hidden sectors */
  149.   dword BPB_tsectors;           /* BPB - sectors on disk (32-bit) */
  150.  
  151.   dword tsize;                  /* Total size for the disk */
  152.  
  153.   byte RW_access;               /* b0 = enable, b1 = write */
  154.   signed char media_change;     /* -1 if media changed, 1 if not */
  155.   word open_files;              /* Number of open files on disk */
  156.   struct dev_hdr _seg *next_drive;  /* Segment of next SRDISK drive */
  157. };
  158.  
  159. #pragma option -a
  160. #pragma pack()
  161.  
  162. struct config_s far *mainconf, far *conf;
  163.  
  164. struct format {                 /* Disk format/configuration description */
  165.   byte RW_access;               /* Read/write access flags */
  166.   int chain_len;                /* Number of drivers chained to this drive */
  167.   dword max_size;               /* Largest possible disk size (truth may be less) */
  168.   dword current_size;           /* Counted current size from the driver chain */
  169.   dword size;                   /* Defined current size */
  170.   int bps;                      /* Bytes per sector */
  171.   int spc;                      /* Sectors per cluster */
  172.   int reserved;                 /* Reserved sectors in the beginning (boot) */
  173.   int FATs;                     /* Number of FAT copies */
  174.   int dir_entries;              /* Directory entries in the root directory */
  175.   int spFAT;                    /* Sectors per FAT */
  176.   dword sectors;                /* Total sectors on drive */
  177.   int FAT_sectors;              /* Total FAT sectors */
  178.   int dir_sectors;              /* Directory sectors */
  179.   int dir_start;                /* First root directory sector */
  180.   int system_sectors;           /* Boot, FAT and root dir sectors combined */
  181.   long data_sectors;            /* Total number of usable data sectors */
  182.   int cluster_size;             /* Size of one cluster in bytes */
  183.   dword clusters;               /* Total number of clusters */
  184.   int FAT_type;                 /* Number of bits in one FAT entry (12 or 16) */
  185. } f;
  186.  
  187. #define MULTIPLEXAH 0x72
  188. #define V_FORMAT 0      /* config_s structure format version used here */
  189.  
  190. #define C_APPENDED  1   /* Capable of having appended drivers */
  191. #define C_MULTIPLE  2   /* Capable of driving many disks */
  192. #define C_32BITSEC  4   /* Capable of handling over 32-bit sector addresses */
  193. #define C_UNKNOWN 0xF8
  194.  
  195. #define READ_ACCESS  1  /* Bit masks for RW_access in IOCTL_msg_s */
  196. #define WRITE_ACCESS 2
  197.  
  198. int root_files = 1;   /* Number of files in root directory */
  199.  
  200. /* Variables possibly supplied in command line */
  201. int drive=0;
  202. int format_f=0;       /* Nonzero if new format given */
  203. int force_f=0;        /* Nonzero if ok to format */
  204. int f_set_env=0;         /* Set environment variables */
  205. int verbose=-1;       /* Verbose: 1 banner, */
  206.                       /* 2 + new format, 3 + old format, 4 + long format */
  207. enum {same, set, clear} write_f = same;    /* Write protect flag */
  208. long disk_size=-1;    /* Size in kilobytes, -1 not set */
  209. int sector_size=-1;   /* Sector size, -1 not set */
  210. int cluster_size=-1;  /* Allocation unit size, -1 not set */
  211. int dir_entries=-1;   /* Directory entries in root directory, -1 not set */
  212. int FATs=-1;          /* FAT copies on the disk */
  213. int media=-1;         /* New media */
  214. int sec_per_track=-1; /* Sectors per track */
  215. int sides=-1;         /* Sides on disk */
  216. int maxKs=0;            /* Top index in maxK[] */
  217. struct {                /* Maximum Kbytes for different drivers in chain */
  218.   dword size;
  219.   int set:1;
  220. } maxK[10];
  221.  
  222.  
  223. /*
  224. **  Declarations
  225. */
  226.  
  227. void print_format(void);
  228. void retrieve_old_format(void);
  229. char *stringisize_flags(int flags);
  230. char *stringisize_memory(int mem);
  231. struct config_s far *conf_ptr(struct dev_hdr _seg *dev);
  232.  
  233. /*
  234. **  SYNTAX
  235. */
  236.  
  237. void print_syntax(void)
  238. {
  239.   fputs(
  240.   "\n"
  241.   "Syntax:  SRDISK [<drive letter>[:]] [<size>] [/F:<DOS disk type>]\n"
  242.   "\t\t[/S:<sector size>] [/C:<cluster size>] [/D:<dir entries>]\n"
  243.   "\t\t[/A:<FAT copies>] [/M:<size>[:<size>[...]]] [/W[-]]\n"
  244.   "\t\t[/V:<verbose>] [/Y] [/E] [/?]\n\n"
  245.  
  246.   "Anything inside [] is optional, the brackets must not be typed.\n"
  247.   "'<something>' must be replaced by what 'something' tells.\n\n"
  248.  
  249.   "<drive letter> specifies the drive that is the RAM disk.\n"
  250.   "<size> determines the disk size in kilobytes.\n"
  251.   "/F:<DOS disk type> may be one of 160, 180, 320, 360, 720, 1200, 1440.\n"
  252.   "/S:<sector size> is a power of 2 in range from 128 to 512 bytes.\n"
  253.   "/C:<cluster size> is a power of 2 in range from 128 to 8192 bytes.\n"
  254.   "/D:<dir entries> is the maximum number of entries in the root directory.\n"
  255.   "/A:<FAT copies> number of File Allocation Tables on disk. 1 is enough.\n"
  256.   "/M List of max memory to allocate by each driver in driver chain\n"
  257.   "/W Write protect disk, /W- enables writes.\n"
  258.   "/V Verbose level from 1 (quiet) to 5 (verbose); default 2.\n"
  259.   "/E Set environment variables SRDISKn (n=1,2,...) to SRDISK drive letters.\n"
  260.   "/Y Yes, destroy the contents.\n"
  261.   "/? This help.\n"
  262.   , stderr);
  263. }
  264.  
  265.  
  266. /*
  267. **  ERROR HANDLING FUNCTIONS
  268. */
  269.  
  270. void syntax(char *err)
  271. {
  272.   fprintf(stderr, "\nSyntax error: %s\n", err);
  273.   print_syntax();
  274.   exit(3);
  275. }
  276.  
  277. void fatal(char *err)
  278. {
  279.   fprintf(stderr, "\nFatal error: %s\n", err);
  280.   exit(1);
  281. }
  282.  
  283. void error(char *err)
  284. {
  285.   fprintf(stderr, "\nError: %s\n", err);
  286.   return;
  287. }
  288.  
  289. void warning(char *err)
  290. {
  291.   fprintf(stderr, "\nWarning: %s\n", err);
  292.   return;
  293. }
  294.  
  295.  
  296. /*
  297. **  COMMAND LINE PARSER
  298. */
  299.  
  300. long parse_narg(char *argp, char **next)
  301. {
  302.   long res;
  303.   if (*argp == ':') argp++, (*next)++;
  304.   res = strtol(argp, next, 10);
  305.   if (argp == *next) return -1L;
  306.   return res;
  307. }
  308.  
  309. int ispow2(int size)
  310. {
  311.   int cmp;
  312.   for (cmp = 128; cmp; cmp <<=1)
  313.     if (cmp == size) return 1;
  314.   return 0;
  315. }
  316.  
  317. void set_DOS_disk(int size)
  318. {
  319.   static struct {
  320.     int disk_size;
  321.     int media;
  322.     int cluster_size;
  323.     int dir_entries;
  324.     int sec_per_track;
  325.     int sides;
  326.   } dos_disk[] = {
  327.     {  160, 0xFE, 512,  64,  8, 1 },
  328.     {  180, 0xFC, 512,  64,  9, 1 },
  329.     {  320, 0xFF,1024, 112,  8, 2 },
  330.     {  360, 0xFD,1024, 112,  9, 2 },
  331.     {  720, 0xF9,1024, 112,  9, 2 },
  332.     { 1200, 0xF9, 512, 224, 15, 2 },
  333.     { 1440, 0xF0, 512, 224, 18, 2 },
  334.     {0}
  335.   };
  336.   int i;
  337.  
  338.   for (i=0; dos_disk[i].disk_size; i++)
  339.     if (dos_disk[i].disk_size == size) {
  340.       disk_size = size;
  341.       cluster_size = dos_disk[i].cluster_size;
  342.       dir_entries = dos_disk[i].dir_entries;
  343.       media = dos_disk[i].media;
  344.       sec_per_track = dos_disk[i].sec_per_track;
  345.       sides = dos_disk[i].sides;
  346.       FATs = 2;
  347.       sector_size = 512;
  348.       format_f++;
  349.       return;
  350.     }
  351.  
  352.   syntax("Unknown DOS disk size");
  353. }
  354.  
  355. void parse_cmdline(int argc, char *argv[])
  356. {
  357.   int arg;
  358.   char *argp;
  359.  
  360.   for(arg=1; arg < argc; arg++) {
  361.     argp = argv[arg];
  362.     while(*argp) {
  363.       if (*argp == '/' || *argp == '-') {
  364.         argp++;
  365.         switch(toupper(*argp++)) {
  366.         case '?':
  367.         case 'H':
  368.           print_syntax();
  369.           exit(0);
  370.         case 'W':
  371.           switch(*argp) {
  372.           case '-': argp++;
  373.                     write_f = clear;
  374.                     break;
  375.           case '+': argp++;
  376.           default:  write_f = set;
  377.           }
  378.           break;
  379.         case 'Y':
  380.           force_f++;
  381.           break;
  382.         case 'S': /* Sector size */
  383.           sector_size = parse_narg(argp, &argp);
  384.           if (!ispow2(sector_size) || sector_size > 512)
  385.             syntax("Invalid sector size");
  386.           format_f++;
  387.           break;
  388.         case 'C': /* Cluster size */
  389.           cluster_size = parse_narg(argp, &argp);
  390.           if (!ispow2(cluster_size) || cluster_size > 8192)
  391.           if (cluster_size % 128 || cluster_size < 128 || cluster_size > 8192)
  392.             syntax("Invalid cluster size");
  393.           format_f++;
  394.           break;
  395.         case 'D': /* Directory entries */
  396.           dir_entries = parse_narg(argp, &argp);
  397.           if (dir_entries < -1 || !dir_entries || dir_entries == 1
  398.           || dir_entries > 1000)
  399.             syntax("Invalid number of directory entries");
  400.           format_f++;
  401.           break;
  402.         case 'A': /* FATs */
  403.           FATs = parse_narg(argp, &argp);
  404.           if (FATs < -1 || !FATs)
  405.             syntax("Invalid number of FAT copies");
  406.           format_f++;
  407.           break;
  408.         case 'F': /* DOS disk format */
  409.           disk_size = parse_narg(argp, &argp);
  410.           set_DOS_disk(disk_size);
  411.           break;
  412.         case 'V': /* Verbose level */
  413.           verbose = parse_narg(argp, &argp);
  414.           if (verbose < 1 || verbose > 5)
  415.             syntax("Invalid verbose level");
  416.           break;
  417.         case 'M': /* MaxK for different partitions */
  418.           maxKs = 0;
  419.           memset(maxK, 0, sizeof maxK);
  420.           do {
  421.             dword size;
  422.             if (maxKs == sizeof maxK / sizeof maxK[0])
  423.               syntax("Too many /M values");
  424.             size = parse_narg(argp, &argp);
  425.             if (size > 0x3FFFFFL)
  426.               syntax("Too large partition size");
  427.             if (size != -1L) {
  428.               maxK[maxKs].size = size;
  429.               maxK[maxKs].set = 1;
  430.             }
  431.             maxKs++;
  432.           } while(*argp == ':');
  433.           break;
  434.         case 'E': /* Set environment variables to show SRDISKs */
  435.           f_set_env = 1;
  436.           break;
  437.         default:
  438.           syntax("Unknown switch");
  439.         }
  440.       }
  441.       else {
  442.         if (*argp == ' ' || *argp == '\t') argp++;
  443.         else if (isdigit(*argp)) {
  444.           disk_size = strtol(argp, &argp, 10);
  445.           if (disk_size < 0 || disk_size > 0x3FFFFFL)
  446.             syntax("Invalid disk size");
  447.           format_f++;
  448.         }
  449.         else {
  450.           if (drive) syntax("Unrecognised character on command line");
  451.           drive = toupper(*argp++)-'A'+1;
  452.           if (drive < 1 || drive > 'Z'-'A'+1) syntax("Invalid drive");
  453.           if (*argp == ':') argp++;
  454.         }
  455.       }
  456.     }
  457.   }
  458. }
  459.  
  460.  
  461. /*
  462. **  Local allocation routine with error check
  463. */
  464.  
  465. void *xalloc(size_t s)
  466. {
  467.   void *b = malloc(s);
  468.   if (!s) fatal("malloc() failed");
  469.   return b;
  470. }
  471.  
  472. /*
  473. **  Get Y/N response
  474. */
  475.  
  476. int getYN(void)
  477. {
  478.   int reply;
  479.  
  480.   if (force_f) reply = 'Y';
  481.   else {
  482.     do reply = toupper(getch());
  483.     while (reply != 'Y' && reply != 'N');
  484.   }
  485.   printf("%c\n", reply);
  486.   if (reply == 'N') return 0;
  487.   return 1;
  488. }
  489.  
  490.  
  491. /*
  492. **  DOS time format conversions
  493. */
  494.  
  495. dword DOS_time(time_t time)
  496. {
  497.   struct tm *ltime;
  498.   union {
  499.     struct {
  500.       word sec2 : 5,
  501.            min : 6,
  502.            hour : 5;
  503.       word day : 5,
  504.            month : 4,
  505.            year : 7;
  506.     } f;
  507.     dword l;
  508.   } file_time;
  509.  
  510.   ltime = localtime(&time);
  511.   file_time.f.sec2 = ltime->tm_sec;
  512.   file_time.f.min = ltime->tm_min;
  513.   file_time.f.hour = ltime->tm_hour;
  514.   file_time.f.day = ltime->tm_mday;
  515.   file_time.f.month = ltime->tm_mon + 1;
  516.   file_time.f.year = ltime->tm_year - 80;
  517.  
  518.   return file_time.l;
  519. }
  520.  
  521. /*
  522. **  Read/Write sector from/to disk
  523. **
  524. **  Return 0 for failure, transferred sector count otherwise
  525. */
  526.  
  527. int xfer_sector(char rw, int count, dword start, void *buffer)
  528. {
  529.   struct config_s far *subconf = conf;
  530.  
  531.   assert(count == 1);   /* We currently support only 1 sector xfers */
  532.  
  533.   while(subconf->sectors <= start) {
  534.     start -= subconf->sectors;
  535.     if ( ! (subconf = conf_ptr(subconf->next)) ) return 0;
  536.   }
  537.  
  538.   /* !!!! Since count is always 1 here, we do not check if the transfer
  539.      continues into the next driver */
  540.  
  541.   _ES = FP_SEG(buffer);     /* <- This messes up the _AX */
  542.   _DI = FP_OFF(buffer);
  543.   _BH = rw;
  544.   _CX = count;
  545.   _DX = start >> 16;
  546.   _AX = start;
  547.   asm {
  548.     push ds
  549.     lds si,subconf
  550.     call dword ptr [si+2]   /* !!!! Configuration format dependent */
  551.     pop ds
  552.   }
  553.   return _AX;
  554. }
  555.  
  556. /*
  557. **  Read sector from disk
  558. **
  559. **  Return 0 for failure, transferred sector count otherwise
  560. */
  561.  
  562. int read_sector(int count, dword start, void *buffer)
  563. {
  564.   return xfer_sector(0, count, start, buffer);
  565. }
  566.  
  567. /*
  568. **  Write sector to disk
  569. **
  570. **  Return 0 for failure, transferred sector count otherwise
  571. */
  572.  
  573. int write_sector(int count, dword start, void *buffer)
  574. {
  575.   return xfer_sector(1, count, start, buffer);
  576. }
  577.  
  578. /*
  579. **  Count the files in root directory
  580. */
  581.  
  582. int count_root(void)
  583. {
  584.   byte *sp;
  585.   int si;
  586.   dword sector = f.dir_start;
  587.   int entries = f.dir_entries;
  588.   int files = 0;
  589.  
  590.   sp = xalloc(f.bps);
  591.  
  592.   while(entries) {
  593.     read_sector(1, sector, sp);
  594.     for(si = 0; si < f.bps && entries; si += 32) {
  595.       if (sp[si] == 0) goto end;    /* Unused, end of directory */
  596.       if (sp[si] != 0xE5            /* Not deleted */
  597.       && !(sp[si+11] & 8))          /* and not label */
  598.         files++;                    /* so it is a file (or directory) */
  599.       entries--;
  600.     }
  601.     sector++;
  602.   }
  603.  
  604.  end:
  605.   free(sp);
  606.   return files;
  607. }
  608.  
  609. /*
  610. **  INITIALIZE DRIVE
  611. */
  612.  
  613. struct config_s far *conf_ptr(struct dev_hdr _seg *dev)
  614. {
  615.   struct config_s far *conf;
  616.   if (!dev) return (void far *)NULL;
  617.   conf = MK_FP(dev, dev->conf);
  618.   if (dev->u.s.ID[0] != 'S'
  619.    || dev->u.s.ID[1] != 'R'
  620.    || dev->u.s.ID[2] != 'D'
  621.    || dev->v_format != V_FORMAT
  622.    || (conf->drive != '$' && (conf->drive < 'A' || conf->drive > 'Z'))
  623.    || !conf->disk_IO
  624.    || !conf->malloc_off)
  625.     fatal("SRDISK devices' internal tables are messed up!");
  626.   return conf;
  627. }
  628.  
  629. void resolve_drive(struct config_s far *conf)
  630. {
  631.   #pragma option -a-
  632.   /* This is drive parameter block for DOS versions 2-3.x */
  633.   struct dpb_s {
  634.     byte  drive;      /* drive number (00h = A:, 01h = B:, etc)               */
  635.     byte  unit;       /* unit number within device driver                     */
  636.     word  bps;        /* bytes per sector                                     */
  637.     byte  hsnwc;      /* highest sector number within a cluster               */
  638.     byte  c2sshift;   /* shift count to convert clusters into sectors         */
  639.     word  ress;       /* number of reserved sectors at beginning of drive     */
  640.     byte  FATs;       /* number of FATs                                       */
  641.     word  dir;        /* number of root directory entries                     */
  642.     word  data;       /* number of first sector containing user data          */
  643.     word  clusters;   /* highest cluster number (number of data clusters + 1) */
  644.     byte  spf;        /* number of sectors per FAT                            */
  645.     word  fdirs;      /* sector number of first directory sector              */
  646.                       /* address of device driver header                      */
  647.     struct config_s far *device;
  648.     byte  media;      /* media ID byte                                        */
  649.     byte  used;       /* 00h if disk accessed, FFh if not                     */
  650.                       /* pointer to next DPB                                  */
  651.     struct dpb_s far *next;
  652.   } far *dbp;
  653.  
  654.   /* DOS 4+ uses different Drive Parameter Block and they should have
  655.      told the drive letters at device initialization anyway.
  656.   */
  657.   if (_osmajor < 4) {
  658.     asm {
  659.         mov ah,0x52     /* SYSVARS call */
  660.         int 0x21        /* Call DOS */
  661.         mov ax,es:[bx]
  662.         mov dx,es:[bx+2]
  663.         mov word ptr dbp,ax
  664.         mov word ptr dbp+2,dx
  665.     }
  666.  
  667.     do {
  668.       if ( dbp->device == MK_FP(FP_SEG(conf), 0) ) {
  669.         conf->drive = dbp->drive + 'A';
  670.         return;
  671.       }
  672.       dbp = dbp->next;
  673.     } while ( FP_OFF(dbp) != 0xFFFF && dbp ); /* && dbp just for luck */
  674.   }
  675.   fatal("SRDISK drive not in DOS Drive Parameter Block chain");
  676. }
  677.  
  678. void init_drive(void)
  679. {
  680.   struct dev_hdr _seg *dev;
  681.  
  682.   _BX = _CX = _DX = 0;
  683.   _AX = MULTIPLEXAH << 8;
  684.  
  685.   asm int 0x2F;
  686.  
  687.   dev = (struct dev_hdr _seg *)_ES;
  688.   if (!dev
  689.    || dev->u.s.ID[0] != 'S'
  690.    || dev->u.s.ID[1] != 'R'
  691.    || dev->u.s.ID[2] != 'D')
  692.   {
  693.     fatal("No SRDISK driver found");
  694.   }
  695.   else if (dev->v_format != V_FORMAT) {
  696.     fatal("Invalid SRDISK driver version");
  697.   }
  698.   conf = mainconf = conf_ptr(dev);
  699.  
  700.   /* Check if driver does not know yet what drive it is */
  701.   do {
  702.     if ( conf->drive == '$' ) {
  703.       resolve_drive(conf);
  704.     }
  705.   } while ( conf = conf_ptr(conf->next_drive) );
  706.   conf = mainconf;
  707.  
  708.   if (drive)
  709.     while(conf->drive != drive-1+'A') {
  710.       if ( ! (conf = conf_ptr(conf->next_drive)) )
  711.         fatal("Drive not ReSizeable RAMDisk");
  712.     }
  713.   else drive = conf->drive-'A'+1;
  714.  
  715.   retrieve_old_format();    /* Setup f */
  716.  
  717.   if (verbose > 3) print_format();
  718.   if (verbose > 4) {
  719.     struct config_s far *subconf = conf;
  720.     int part = 1;
  721.     for( ; subconf; subconf = conf_ptr(subconf->next), part++) {
  722.       printf("Driver %d of %d\n"
  723.              "  Version %.4Fs\n"
  724.              "  Memory: %.4Fs\n"
  725.              "  Flags:%s\n"
  726.              "  Max size: %luK\n"
  727.              "  Size: %luK\n"
  728.              "  Sectors: %lu\n\n"
  729.              ,part, f.chain_len
  730.              ,((struct dev_hdr _seg *)FP_SEG(subconf))->u.s.version
  731.              ,((struct dev_hdr _seg *)FP_SEG(subconf))->u.s.memory
  732.              ,stringisize_flags(subconf->flags)
  733.              ,subconf->maxK
  734.              ,subconf->size
  735.              ,subconf->sectors
  736.              );
  737.     }
  738.   }
  739. }
  740.  
  741. /*
  742. **  SET MAX KBYTES FOR DRIVERS IN CHAIN
  743. */
  744.  
  745. void setmaxK(void)
  746. {
  747.   struct config_s far *subconf;
  748.   int i = 0;
  749.  
  750.   if (maxKs > f.chain_len) {
  751.     error("Too many /M values");
  752.     return;
  753.   }
  754.  
  755.   for (subconf = conf;
  756.        subconf && i < maxKs;
  757.        subconf = conf_ptr(subconf->next), i++)
  758.   {
  759.     if (maxK[i].set) subconf->maxK = maxK[i].size;
  760.   }
  761.  
  762.   f.max_size = 0;
  763.   for (subconf = conf; subconf; subconf = conf_ptr(subconf->next) ) {
  764.     f.max_size += subconf->maxK;
  765.   }
  766.  
  767.   if (verbose > 1) {
  768.     printf("\nAdjusted max allocation sizes");
  769.     if (!format_f) printf(" - reformat disk to enable change");
  770.     puts("");
  771.   }
  772. }
  773.  
  774.  
  775. /*
  776. **  SET WRITE PROTECT
  777. */
  778.  
  779. void set_write_protect()
  780. {
  781.   switch(write_f) {
  782.   case set:
  783.     conf->RW_access &= ~WRITE_ACCESS;
  784.     if (verbose > 1)
  785.       printf("\nWrite protect enabled\n");
  786.     break;
  787.   case clear:
  788.     conf->RW_access |= WRITE_ACCESS;
  789.     if (verbose > 1)
  790.       printf("\nWrite protect disabled\n");
  791.     break;
  792.   }
  793. }
  794.  
  795. /*
  796. **  FORMAT DISK
  797. */
  798.  
  799. int licence_to_kill(void)
  800. {
  801.   if (!force_f && root_files) {
  802.     int reply;
  803.     printf("\n\aAbout to destroy all files on drive %c!\n\a"
  804.            "Continue (Y/N) ? ", drive-1+'A');
  805.     if (!getYN()) {
  806.       printf("\nOperation aborted\n");
  807.       return 0;
  808.     }
  809.   }
  810.   return 1;
  811. }
  812.  
  813.  
  814. /*
  815. **  Format printing
  816. */
  817.  
  818. char *stringisize_flags(int flags)
  819. {
  820.   static char _string[60];
  821.   _string[0] = 0;
  822.   if (flags & C_APPENDED) strcat(_string, " APPENDED");
  823.   if (flags & C_MULTIPLE) strcat(_string, " MULTIPLE");
  824.   if (flags & C_32BITSEC) strcat(_string, " 32BITSEC");
  825.   if (flags & C_UNKNOWN) strcat(_string, " unknown");
  826.   return _string;
  827. }
  828.  
  829. void print_format(void)
  830. {
  831.   printf("\n"
  832.          "Drive %c:\n"
  833.          "  Disk size: %luK\n"
  834.          "  Cluster size: %d bytes\n"
  835.          "  Sector size: %d bytes\n"
  836.          "  Directory entries: %d\n"
  837.          "  FAT copies: %d\n"
  838.          "  Bytes available: %ld\n"
  839.          "  Write protection: %s\n"
  840.          ,drive-1+'A'
  841.          ,f.size
  842.          ,f.cluster_size
  843.          ,f.bps
  844.          ,f.dir_entries
  845.          ,f.FATs
  846.          ,f.clusters*f.cluster_size
  847.          ,((f.RW_access & WRITE_ACCESS) ? "OFF" : "ON")
  848.          );
  849.   if (verbose > 3)
  850.     printf("  Sectors: %lu\n"
  851.            "  Reserved sectors: %d\n"
  852.            "  FAT sectors: %d\n"
  853.            "  Directory sectors: %d\n"
  854.            "  Sectors per cluster: %d\n"
  855.            "  Clusters: %lu\n"
  856.            "  FAT type: %u bit\n"
  857.            "  Max size: %luK\n"
  858.            ,f.sectors
  859.            ,f.reserved
  860.            ,f.FAT_sectors
  861.            ,f.dir_sectors
  862.            ,f.spc
  863.            ,f.clusters
  864.            ,f.FAT_type
  865.            ,f.max_size
  866.            );
  867. }
  868.  
  869.  
  870. /*
  871. **  RETRIEVE OLD FORMAT FOR DISK
  872. */
  873.  
  874. void retrieve_old_format(void)
  875. {
  876.   struct config_s far *subconf;
  877.  
  878.   memset(&f, 0, sizeof f);
  879.  
  880.   /* Scan the chain of drivers linked to the same drive */
  881.   for (subconf = conf; subconf; subconf = conf_ptr(subconf->next)) {
  882.     /* Make sure f.max_size does not overflow */
  883.     if (f.max_size && -f.max_size <= subconf->maxK)
  884.       f.max_size = -1;
  885.     else
  886.       f.max_size += subconf->maxK;
  887.     f.current_size += subconf->size;
  888.     f.chain_len++;
  889.   }
  890.  
  891.   f.RW_access = conf->RW_access;
  892.   f.size = conf->tsize;
  893.   f.bps = conf->BPB_bps;
  894.   f.spc = conf->BPB_spc;
  895.   f.reserved = conf->BPB_reserved;
  896.   f.FATs = conf->BPB_FATs;
  897.   f.dir_entries = conf->BPB_dir;
  898.   f.spFAT = conf->BPB_FATsectors;
  899.   f.sectors = conf->BPB_tsectors;
  900.   f.FAT_sectors = f.spFAT * f.FATs;
  901.   f.dir_sectors = f.dir_entries * 32 / f.bps;
  902.   f.dir_start = f.reserved + f.FAT_sectors;
  903.   f.system_sectors = f.dir_start + f.dir_sectors;
  904.   f.cluster_size = f.spc * f.bps;
  905.   if (f.size) {
  906.     f.data_sectors = f.sectors - f.system_sectors;
  907.     f.clusters = f.data_sectors / f.spc;
  908.   }
  909.   f.FAT_type = f.clusters > 4086 ? 16 : 12;
  910.  
  911.   if (sec_per_track == -1) sec_per_track = conf->BPB_spt;
  912.   if (sides == -1) sides = conf->BPB_heads;
  913. }
  914.  
  915. /*
  916. **  COUNT FORMAT FOR DISK
  917. **
  918. **  Return 0 if format is impossible
  919. */
  920.  
  921. int count_new_format(psize, pcluster_size, psector_size, pdir_entries, pFATs)
  922. long psize;
  923. int pcluster_size, psector_size, pdir_entries, pFATs;
  924. {
  925.   f.FAT_type = 12;        /* By default try to use 12 bit FAT */
  926.  
  927.   f.size = psize;
  928.   f.cluster_size = pcluster_size;
  929.   f.bps = psector_size;
  930.   f.dir_entries = pdir_entries;
  931.   f.FATs = pFATs;
  932.  
  933.   /* Make sure sectors are big enough for the disk */
  934.   while((f.sectors = f.size * 1024 / f.bps) >
  935.       ((conf->flags & C_32BITSEC) ? 0x7FFFFF : 0xFFFFL) )
  936.     f.bps <<= 1;
  937.   if (f.bps > 512)
  938.     warning("Sector size larger than 512 bytes, may crash DOS");
  939.  
  940.   if (f.cluster_size < f.bps)
  941.     f.cluster_size = f.bps;
  942.  
  943.   { div_t divr;
  944.     divr = div(f.dir_entries * 32, f.bps);
  945.     f.dir_sectors = divr.quot + (divr.rem ? 1 : 0);
  946.   }
  947.  
  948.   count_clusters:
  949.   f.system_sectors = f.reserved + f.dir_sectors;
  950.   f.data_sectors = max(f.sectors - f.system_sectors, 0);
  951.  
  952.   f.spc = f.cluster_size / f.bps;
  953.  
  954.   { ldiv_t divr;
  955.     divr = ldiv(((long)f.data_sectors + 2 * f.spc) * f.FAT_type,
  956.                 (long)8 * f.cluster_size + f.FATs * f.FAT_type);
  957.     f.spFAT = divr.quot + (divr.rem ? 1 : 0);
  958.   }
  959.  
  960.   f.FAT_sectors = f.spFAT * f.FATs;
  961.   f.system_sectors += f.FAT_sectors;
  962.   f.data_sectors = max(f.data_sectors - f.FAT_sectors, 0);
  963.  
  964.   f.clusters = f.data_sectors / f.spc;
  965.  
  966.   /* Make sure we use the right FAT type */
  967.   if (f.FAT_type < 16 && f.clusters > 4077) {
  968.     f.FAT_type = 16;
  969.     goto count_clusters;
  970.   }
  971.   if (f.FAT_type > 12 && f.clusters < 4088 || f.clusters > 65518) {
  972.     f.FAT_type = 12;
  973.     f.cluster_size <<= 1;
  974.     goto count_clusters;
  975.   }
  976.  
  977.   f.dir_start = f.reserved + f.FAT_sectors;
  978.  
  979.   /* If Disk will be disabled */
  980.   if (!f.size) {
  981.     f.data_sectors = 0;
  982.     f.clusters = 0;
  983.     return 1;
  984.   }
  985.  
  986.   if (f.sectors <= f.system_sectors || !f.clusters)
  987.     return 0;
  988.  
  989.   return 1;
  990. }
  991.  
  992. /*
  993. **  CONFIGURE DRIVE FOR FORMAT f
  994. **
  995. **  Disable drive and configure it. RW_access must be set by caller.
  996. **
  997. **  Return 0 if format is impossible
  998. */
  999.  
  1000. int configure_drive(void)
  1001. {
  1002.   long Kleft = f.size;
  1003.   struct config_s far *subconf;
  1004.   dword alloc, lastalloc;
  1005.   int err = 0;
  1006.   dword (far *dmalloc)(dword);  /* Make here the pointer to driver's malloc */
  1007.   int old_access = conf->RW_access;
  1008.  
  1009.   conf->RW_access = 0;  /* Disable DOS access to drive */
  1010.  
  1011.   if (f.size != f.current_size) {
  1012.     for(subconf = conf; subconf; subconf = conf_ptr(subconf->next)) {
  1013.       alloc = max(min(subconf->maxK, Kleft), 0);
  1014.       dmalloc = MK_FP(FP_SEG(subconf), subconf->malloc_off);
  1015.       lastalloc = dmalloc(alloc);
  1016.       if (lastalloc != alloc && (err = !lastalloc) != 0) break;
  1017.       subconf->size = lastalloc;
  1018.       subconf->sectors = (long)lastalloc * 1024 / f.bps;
  1019.  
  1020.       Kleft -= lastalloc;
  1021.     }
  1022.  
  1023.     if (Kleft > 0) {    /* If not enough memory could be allocated */
  1024.       err = 1;
  1025.       if (!conf->next) {   /* If single drive, try to preserve it */
  1026.         /* If single drive, dmalloc is still valid */
  1027.         if (dmalloc(f.current_size) == f.current_size) {  /* Make it the old size */
  1028.           conf->size = f.current_size;          /* Fix back what was changed */
  1029.           conf->sectors = (long)f.current_size * 1024 / f.bps;
  1030.           conf->RW_access = old_access;   /* Enable the disk */
  1031.           error("Failed to allocate memory");
  1032.           return 0;                       /* Return failure */
  1033.         }
  1034.       }
  1035.       /* Free all memory */
  1036.       for (subconf = conf; subconf; subconf = conf_ptr(subconf->next)) {
  1037.         dmalloc = MK_FP(FP_SEG(subconf), subconf->malloc_off);
  1038.         if (!dmalloc(0)) {
  1039.           subconf->size = 0;
  1040.           subconf->sectors = 0;
  1041.         }
  1042.       }
  1043.       f.size = 0;
  1044.       f.sectors = 0;
  1045.       error("Failed to allocate memory - disk disabled");
  1046.     }
  1047.  
  1048.     if (Kleft < 0 && verbose > 1)
  1049.       printf("\n%ldKbytes extra allocated,\n"
  1050.              "Perhaps you should make your disk that much larger.\n"
  1051.              ,-Kleft);
  1052.   }
  1053.  
  1054.   for(subconf = conf; subconf; subconf = conf_ptr(subconf->next))
  1055.     subconf->BPB_bps = f.bps;
  1056.  
  1057.   conf->BPB_spc = f.spc;
  1058.   conf->BPB_reserved = f.reserved;
  1059.   conf->BPB_FATs = f.FATs;
  1060.   conf->BPB_dir = f.dir_entries;
  1061.   conf->BPB_sectors = (conf->flags & C_32BITSEC && f.sectors > 0xFFFEL) ?
  1062.                       0 : f.sectors;
  1063.   conf->BPB_media = media == -1 ? 0xFA : media;
  1064.   conf->BPB_FATsectors = f.spFAT;
  1065.   conf->BPB_spt = sec_per_track;
  1066.   conf->BPB_heads = sides;
  1067.   conf->BPB_hidden = 0L;
  1068.   conf->BPB_tsectors = f.sectors;
  1069.   conf->tsize = f.size;
  1070.   conf->open_files = 0;
  1071.   if (format_f) conf->media_change = -1;
  1072.  
  1073.   return !err;
  1074. }
  1075.  
  1076. void format_disk(void)
  1077. {
  1078.   long old_disk_size = f.size;
  1079.   ldiv_t ldivr;
  1080.   int Fsec;
  1081.   int i;
  1082.   byte *sector;
  1083.  
  1084.   if (disk_size == -1) disk_size = conf->size;
  1085.   if (disk_size > f.max_size) {
  1086.     error("Not enough memory for disk available");
  1087.     return;
  1088.   }
  1089.  
  1090.   if (!force_f && conf->open_files) {
  1091.     error("Files open on drive");
  1092.     return;
  1093.   }
  1094.  
  1095.   /* Count root files before f is messed by count_new_format() */
  1096.   root_files = count_root();
  1097.  
  1098.   if (!count_new_format(disk_size,
  1099.                         cluster_size == -1 ? conf->BPB_bps * conf->BPB_spc
  1100.                                            : cluster_size,
  1101.                         sector_size == -1  ? conf->BPB_bps : sector_size,
  1102.                         dir_entries == -1  ? conf->BPB_dir : dir_entries,
  1103.                         FATs == -1         ? conf->BPB_FATs : FATs))
  1104.   {
  1105.     error("Impossible format for disk");
  1106.     return;
  1107.   }
  1108.  
  1109.   /* If Disk will be disabled */
  1110.   if (!f.size) {
  1111.     if (!old_disk_size) {
  1112.       /* If was disabled also before */
  1113.       configure_drive();
  1114.       if (verbose > 1) printf("\nNew configuration saved for later use\n");
  1115.     } else {
  1116.       /* If disk now get's disabled */
  1117.       if (!licence_to_kill()) return;
  1118.       configure_drive();
  1119.       if (verbose > 1) printf("\nRAMDisk disabled\n");
  1120.     }
  1121.     return;
  1122.   }
  1123.   if (verbose > 1) {
  1124.     printf("\nNew disk configuration:\n");
  1125.     print_format();
  1126.   }
  1127.  
  1128.   if (old_disk_size && !licence_to_kill()) return;
  1129.  
  1130.   /* Request the new disk space and configure the driver(s) */
  1131.   if (!configure_drive()) return;
  1132.  
  1133.   sector = xalloc(f.bps);
  1134.  
  1135.   /* Write the new disk */
  1136.  
  1137.   /* Make the boot sector */
  1138.   memset(sector, 0, f.bps);
  1139.   *(word  *)sector = 0x3CEB;                /* Boot record JMP instruction */
  1140.   *(byte  *)(sector+2) = 0x90;              /* NOP instruction */
  1141.   memcpy(sector+3, "SRD "VERSION, 8);       /* OEM code and version */
  1142.   *(word  *)(sector+11) = f.bps;
  1143.   *(byte  *)(sector+13) = f.spc;
  1144.   *(word  *)(sector+14) = f.reserved;
  1145.   *(byte  *)(sector+16) = f.FATs;
  1146.   *(word  *)(sector+17) = f.dir_entries;
  1147.   *(word  *)(sector+19) = conf->BPB_sectors;/* Sectors (16-bit) */
  1148.   *(byte  *)(sector+21) = conf->BPB_media;  /* Media */
  1149.   *(word  *)(sector+22) = f.spFAT;
  1150.   *(word  *)(sector+24) = sec_per_track;    /* Sectors per track */
  1151.   *(word  *)(sector+26) = sides;            /* Sides */
  1152.   *(dword *)(sector+28) = 0;                /* Hidden sectors */
  1153.   *(dword *)(sector+32) = f.sectors;        /* Total number of sectors */
  1154.   *(byte  *)(sector+36) = -1;               /* Physical drive number */
  1155.   *(byte  *)(sector+37) = 0;                /* reserved */
  1156.   *(byte  *)(sector+38) = 0x29;             /* Signature byte */
  1157.   *(dword *)(sector+39) = time(NULL);       /* Serial number */
  1158.   _fmemcpy(sector+43,
  1159.            ((struct dev_hdr far *)MK_FP(FP_SEG(conf), 0))->u.volume,
  1160.            11);                             /* Volume label */
  1161.   memcpy(sector+54, f.FAT_type == 12 ? "FAT12   " :
  1162.                     f.FAT_type == 16 ? "FAT16   " : "        "
  1163.                    ,8);
  1164.   *(word  *)(sector+62) = 0xFEEB;           /* Boot code (JMP $) */
  1165.   *(word  *)(sector+f.bps-2) = 0xAA55;      /* Validity code */
  1166.   write_sector(1, 0, sector);           /* Write boot sector */
  1167.  
  1168.   for (i = 0; i < f.FATs; i++) {
  1169.     word sector_n =
  1170.         f.reserved + f.spFAT * i;
  1171.     /* Write 1st FAT sector */
  1172.     memset(sector, 0, f.bps);  /* Make 1st FAT sector */
  1173.     ((dword *)sector)[0] =
  1174.       (f.FAT_type == 12 ? 0xFFFF00L : 0xFFFFFF00L) | conf->BPB_media;
  1175.     write_sector(1, sector_n++, sector);
  1176.  
  1177.     /* Write FAT sectors from 2nd to last */
  1178.     ((dword *)sector)[0] = 0L;
  1179.     for (Fsec = 1; Fsec < f.spFAT; Fsec++)
  1180.         write_sector(1, sector_n++, sector);
  1181.   }
  1182.  
  1183.   /* Write 1st directory sector */
  1184.   f.dir_start = f.reserved + f.FAT_sectors;
  1185.   _fmemcpy(sector, ((struct dev_hdr far *)MK_FP(FP_SEG(conf), 0))->u.volume, 11);
  1186.   sector[11] = FA_LABEL;
  1187.   *(dword *)(sector+22) = DOS_time(time(NULL));
  1188.   write_sector(1, f.dir_start, sector);
  1189.  
  1190.   /* Write directory sectors from 2nd to last */
  1191.   memset(sector, 0, 16);
  1192.   for (Fsec = 1; Fsec < f.dir_sectors; Fsec++)
  1193.       write_sector(1, f.dir_start+Fsec, sector);
  1194.  
  1195.   conf->RW_access = READ_ACCESS | (write_f == set ? 0 : WRITE_ACCESS);
  1196.  
  1197.   free(sector);
  1198.  
  1199.   if (verbose > 1) printf("\nDisk formatted\n");
  1200. }
  1201.  
  1202. /*
  1203. **  Main environment setting
  1204. */
  1205.  
  1206. /*
  1207.    envptr - returns pointer to parent command.com's copy of the environment
  1208.    Provided by Doug Dougherty, original source by S. Palmer.
  1209. */
  1210. char far *
  1211. envptr(size)
  1212. int *size;
  1213. {
  1214.     int parent_p;
  1215.  
  1216. /*  memory control block */
  1217.  
  1218.     #pragma option -a-
  1219.     struct MCB {
  1220.         char id;
  1221.         unsigned int owner;
  1222.         unsigned int size;
  1223.     } far *mcb;
  1224.     #pragma option -a
  1225.  
  1226.     parent_p=peek(_psp,0x16);    /* find pointer to parent in psp */
  1227.     if (peek(parent_p,0x2c)==0) {
  1228.        mcb = (struct MCB far *) (((long) (peek(parent_p-1,0x3) + parent_p)) << 16);
  1229.     }
  1230.     else {
  1231.        mcb = (struct MCB far *) (((long) (peek(parent_p,0x2c) - 1)) << 16);
  1232.     }
  1233.     *size = mcb->size * 16;
  1234.     return (char far *)MK_FP(FP_SEG(mcb) + 1, 0);
  1235. }
  1236.  
  1237. /*
  1238.    msetenv - place an environment variable in command.com's copy of
  1239.              the envrionment.
  1240.    Provided by Doug Dougherty, original source by S. Palmer.
  1241. */
  1242. int
  1243. msetenv(var,value)
  1244. char *var, *value;
  1245. {
  1246.     char far *env1, far *env2;
  1247.     char far *cp;
  1248.     int size;
  1249.     int l;
  1250.  
  1251.     env1 = env2 = envptr(&size);
  1252.     l = strlen(var);
  1253.     strupr(var);
  1254.  
  1255.     /*
  1256.        Delete any existing variable with the name (var).
  1257.     */
  1258.     while (*env2) {
  1259.         if ((_fstrncmp(var,env2,l) == 0) && (env2[l] == '=')) {
  1260.             cp = env2 + _fstrlen(env2) + 1;
  1261.             _fmemcpy(env2,cp,size-(cp-env1));
  1262.         }
  1263.         else {
  1264.             env2 += _fstrlen(env2) + 1;
  1265.         }
  1266.     }
  1267.  
  1268.     /*
  1269.        If the variable fits, shovel it in at the end of the envrionment.
  1270.     */
  1271.     if (_fstrlen(value) && (size-(env2-env1)) >= (l + _fstrlen(value) + 3)) {
  1272.         _fstrcpy(env2,var);
  1273.         _fstrcat(env2,"=");
  1274.         _fstrcat(env2,value);
  1275.         env2[_fstrlen(env2)+1] = 0;
  1276.         return(0);
  1277.     }
  1278.  
  1279.     /*
  1280.        Return error indication if variable did not fit.
  1281.     */
  1282.     return(-1);
  1283. }
  1284.  
  1285. void set_env()
  1286. {
  1287.     struct config_s far *conf = mainconf;
  1288.     char var[] = "SRDISK1";
  1289.     char drive[] = "A";
  1290.  
  1291.     if (verbose > 1) puts("");
  1292.     do {
  1293.       drive[0] = conf->drive;
  1294.       if (verbose > 1) printf("Set %s=%s\n", var, drive);
  1295.       if (msetenv(var, drive))
  1296.         fatal("Not enough environment space");
  1297.       var[6]++;
  1298.     } while ( conf = conf_ptr(conf->next_drive) );
  1299. }
  1300.  
  1301. /*
  1302. **  MAIN FUNCTION
  1303. */
  1304.  
  1305. int main(int argc, char *argv[])
  1306. {
  1307.   printf("ReSizeable RAMDisk Formatter version "VERSION". "
  1308.          "Copyright (c) 1992 Marko Kohtala.\n");
  1309.  
  1310.   if (argc > 1) parse_cmdline(argc, argv);
  1311.   else if (verbose > 1) printf("\nFor help type 'SRDISK /?'.\n");
  1312.  
  1313.   if (verbose == -1) verbose = 2;
  1314.  
  1315.   init_drive();             /* Get pointer to driver configuration */
  1316.  
  1317.   if (f_set_env) set_env();
  1318.  
  1319.   if (maxKs) setmaxK();
  1320.  
  1321.   if (format_f) format_disk();
  1322.   else if (write_f != same) set_write_protect();
  1323.   else if (!f_set_env && verbose < 4 && verbose > 1) {
  1324.     if (f.size) print_format();
  1325.     else printf("\nDrive %c: disabled\n", drive-1+'A');
  1326.   }
  1327.  
  1328.   return 0;
  1329. }
  1330.  
  1331.